<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>飞机大战</title>
    <style>
        html,
        body {
            margin: 0;
            padding: 0;
        }

        .box,
        .game {
            width: 320px;
            height: 568px;
        }

        .box {
            background: url('./image/start-background.png');
            /* position: static; 就是不能默认值 */
            position: relative;
        }

        .begin {
            width: 120px;
            background-color: #fff;
            height: 30px;
            line-height: 30px;
            text-align: center;
            border-radius: 15px;
            /* 位置的定位 */
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
            bottom: -400px;
            margin: auto;
            cursor: pointer;
        }

        .game {
            display: none;
            background: url('./image/background_1.png');
            position: absolute;
            left: 0;
            top: 0;
        }

        .score-box {
            display: none;
            width: 120px;
            height: 60px;
            line-height: 60px;
            text-align: center;
            background-color: rgba(56, 151, 176, .5);
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
        }
    </style>
</head>

<body>
    <!-- 一开始的背景图 -->
    <div class="box">
        <div class="begin">开始游戏</div>
    </div>
    <div class="game">
        <!-- 两个得分 -->
        <div>得分:<span class="scorel">0</span></div>
        <div class="score-box">
            <div>得分:<span class="score2">0</span></div>
        </div>
        <!-- 游戏中的所有飞机加入到这里 -->
    </div>
    <script>
        var MY_PLANE = 0,
            ENEMY = 1,
            BULLET = 2;

        //公共方法
        function $(selector) {
            return document.querySelector(selector);
        }

        function randomByLimit(start = 30, end = 100) {
            //四舍五入 随机数:0-1不含1
            return start + Math.round(Math.random() * (end - start));
        }
        var begin = $('.begin'),
            game = $('.game'),
            maxWidth, //启动时赋值
            maxHeight,
            myPlane,
            //计分
            score1 = $('.scorel'),
            score2 = $('.score2'),
            scoreBox = $('.score-box'),
            gm; //游戏管理器

        //创建飞行器
        //基本属性构成
        //[血量] hp
        //[速度] speed
        //[图片] img
        //[尺寸] size:{w,h}
        //[类型]type
        //[位置]offset:{x,y}

        //[方向] 不同类别的时候做不同的移动
        function Flyer(hp, speed, img, size, type, offset, direction) {
            this.hp = hp;
            this.speed = speed;
            this.img = img;
            this.size = size;
            this.type = type;
            this.offset = offset;
            this.direction = direction;
            this.createDOM();
        }
        Flyer.prototype.createDOM = function () {
            // 1: 创建元素
            var element = document.createElement('img');
            // 2: 配置元素样式 = 宽高 + 位置 + src图片
            element.width = this.size.w;
            element.height = this.size.h;
            element.style.position = 'absolute';
            element.style.left = this.offset.x + 'px';
            element.style.top = this.offset.y + 'px';
            element.src = this.img;
            // 3: 加入到game元素中
            game.appendChild(element);
            // 4: 为了能更好的操作js对象与dom之间的引用,相互保存一下
            this.ele = element;
            element.obj = this;
        }
        //移动
        Flyer.prototype.move = function () {
            let isLive = true
            // 做方向的区分,而无需做类型的区分
            switch (this.direction) {
                case 'w':
                    if (isLive = this.offset.y > 0) {
                        this.offset.y -= this.speed;
                        this.ele.style.top = this.offset.y + 'px';
                    }
                    break;
                case 's':
                    if (isLive = this.offset.y < (maxHeight - this.size.h)) {
                        this.offset.y += this.speed;
                        this.ele.style.top = this.offset.y + 'px';
                    }
                    break;
                case 'a':
                    if (isLive = this.offset.x > 0) {
                        this.offset.x -= this.speed;
                        this.ele.style.left = this.offset.x + 'px';
                    }
                    break;
                case 'd':
                    if (isLive = this.offset.x < (maxWidth - this.size.w)) {
                        this.offset.x += this.speed;
                        this.ele.style.left = this.offset.x + 'px';
                    }
                    break;
            }
            //判断当前元素是否需要销毁
            ///主战机  只需要不移动而不会因为移动而销毁
            if (this.type !== MY_PLANE) {
                if (!isLive) this.Kill();
            }
            //判断是否产生撞击
            this.impact(this.offset.x, this.offset.y);
        }
        Flyer.prototype.Kill = function () {
            if (!this.ele) return;
            //Js相关的DoM元素干掉
            this.ele.remove();
            //Js相关的定时器需要干掉
            clearInterval(this.timer);
            //Js元素干掉
            this.ele.obj = null //this
            this.ele = null //DOM
        }
        //判断是否产生撞击
        Flyer.prototype.impact = function (x, y) {
            var eles = document.elementsFromPoint(x, y),
                all = {},
                imgCount = 0;
            eles.forEach(e => {
                if (e.tagName === 'IMG') {
                    //类型划分
                    //6个IMG 子弹2 敌机2 我机1个
                    //最多 子弹1个 敌机1 我机1个
                    //假设：子弹+敌机=双爆
                    //      子弹+我机=不处理
                    //      敌机+我机=我机 减血 敌机自爆
                    all[e.obj.type] = e.obj //{MY_PLANE:true}
                    imgCount++;
                }
            });
            //优化思路：大多数情况都是一个元素img
            if (imgCount === 1) {
                return //就一个人
            }
            //存在主战机
            if (all[MY_PLANE] && all[ENEMY]) {
                all[ENEMY].Kill()
                all[MY_PLANE].hp--;
                // console.log('扣血');
            } else if (all[BULLET] && all[ENEMY]) {
                all[ENEMY].Kill()
                all[BULLET].Kill()
                // console.log('加分');
                //成绩加分
                score1.innerText -= -1;
            }
            if (myPlane.hp < 1) {
                myPlane.Kill()
                gm.gameOver()
            }
        }
        //主战机
        function MyPlane(hp, speed, img, size, type, offset) {
            Flyer.call(this, hp, speed, img, size, type, offset);
            this.moveBefore()
        }

        //派生继承
        MyPlane.prototype = Object.create(Flyer.prototype); //继承了他的方法
        // 防止被覆盖
        MyPlane.prototype.moveBefore = function () {
            keyPressFunction = (function (event) {
                //决定这个飞机的direction 方向
                switch (event.key) {
                    case 's':
                    case 'w':
                    case 'a':
                    case 'd':
                        this.direction = event.key;
                        this.move();
                }
            }).bind(this)
            //可以添加多个函数，但是移除时函数必须统一
            window.addEventListener('keypress', keyPressFunction)
            //只能一个函数移除= null可读性没有上述的好
            // window.onkeypress = keypressFunctin;
        }
        //掰回来
        MyPlane.constructor = MyPlane;

        //游戏管理器GM GameMaster
        function GameMaster() {}
        //游戏开始
        GameMaster.prototype.start = function () {
            game.style.display = 'block';
            //产生飞机等...
            maxWidth = game.offsetWidth;
            maxHeight = game.offsetHeight;
            enemyTime = setInterval(function () {
                var x = randomByLimit(0, maxWidth - 34)
                var enemy = new Flyer(1, 10, './image/small-plane.png', {
                    w: 34,
                    h: 24
                }, ENEMY, {
                    x: x,
                    y: 0
                }, 's');
                enemy.timer = setInterval(enemy.move.bind(enemy), 200)
            }, 500)
            myPlane = new MyPlane(10, 10, './image/my-plane.gif', {
                w: 66,
                h: 80
            }, MY_PLANE, {
                x: 160 - 33,
                y: maxHeight - 80,
            });
            //创建子弹
            bulletTimer = setInterval(function () {
                var bullet = new Flyer(1, 30, './image/bullet1.png', {
                    w: 6,
                    h: 14
                }, BULLET, {
                    x: myPlane.offset.x + myPlane.size.w / 2 - 6,
                    y: myPlane.offset.y - 20,
                }, 'w')
                bullet.timer = setInterval(bullet.move.bind(bullet), 50)
            }, 500)
        }
        //游戏结束
        GameMaster.prototype.gameOver = function () {
            //把score1的值赋值给 score2
            score2.innerText = score1.innerText;
            scoreBox.style.display = 'block';
            //停止相关定时器
            clearInterval(bulletTimer);
            clearInterval(enemyTime);
            //清除键盘事件
            window.removeEventListener('keypress', keyPressFunction)
            // window.onkeypress=null;//上述可读性 和 功能性会更好
        }
        gm = new GameMaster();
        begin.onclick = function () {
            gm.start();
        }
        //可飞行的 => 飞机 = 我方飞机 ＋ 地方飞机 ＋ 子弹
    </script>
</body>

</html>